home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1993, 1994, Silicon Graphics, Inc.
- * All Rights Reserved.
- *
- * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
- * the contents of this file may not be disclosed to third parties, copied or
- * duplicated in any form, in whole or in part, without the prior written
- * permission of Silicon Graphics, Inc.
- *
- * RESTRICTED RIGHTS LEGEND:
- * Use, duplication or disclosure by the Government is subject to restrictions
- * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
- * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
- * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
- * rights reserved under the Copyright Laws of the United States.
- */
- /* csg.c
- *
- * demos implementation of boolean operations with stencil planes.
- *
- * csg.c draws a CSG object - a cube with a hole drilled through the
- * center. The stencil planes are used to determine where the cube
- * should be drawn and where the cylinder should be drawn.
- * There are several things to bear in mind. The cube is drawn
- * "normally"; that is, with its back faces removed. The cylinder is
- * subtracted from the cube, so only its BACK faces will show. Also,
- * the cube is NOT drawn wherever it is inside the cylinder. The stencil
- * planes and the z-buffer are used together to figure out where the
- * cube is inside the cylinder.
- */
-
- #include <gl/gl.h>
- #include <gl/device.h>
- #include <stdio.h>
- #include <math.h>
-
-
- void def_simple_light_calc(void);
- void use_simple_light_calc(void);
- void main(void);
- void initialize(void);
- void drawscene(void);
- void scrrect(void);
- void fcube(void);
-
-
- float red_material[] = {
- DIFFUSE, 0.8, 0.0, 0.0,
- SPECULAR, 1.0, 1.0, 1.0,
- SHININESS, 128.0,
- LMNULL };
-
- float shiny_material[] = {
- DIFFUSE, 0.4, 0.4, 0.0,
- SPECULAR, 1.0, 1.0, 1.0,
- SHININESS, 128.0,
- LMNULL };
-
- float blue_material[] = {
- AMBIENT, 0.4, 0.4, 0.4,
- DIFFUSE, 0.0, 0.0, 1.0,
- SPECULAR, 0.0, 1.0, 1.0,
- SHININESS, 45.0,
- LMNULL };
-
- float two_side[] = {
- TWOSIDE, 1.0,
- LMNULL };
-
- void
- def_simple_light_calc(void){
- lmdef(DEFMATERIAL, 1, 11, shiny_material);
- lmdef(DEFMATERIAL, 2, 15, blue_material);
- lmdef(DEFMATERIAL, 3, 11, red_material);
- lmdef(DEFLIGHT, 1, 0, NULL);
- lmdef(DEFLMODEL, 1, 3, two_side);
- }
-
- void
- use_simple_light_calc(void){
- lmbind(LIGHT0, 1);
- lmbind(LMODEL, 1);
- }
-
-
-
- /* default cube size */
- #define CUBE_X 1.0
- #define CUBE_Y 1.0
- #define CUBE_Z 1.0
-
- /* three dimensional vector */
- typedef float vector[3];
-
- /* cube vectors */
- static vector front = { 0.0, 0.0, 1.0};
- static vector back = { 0.0, 0.0, -1.0};
- static vector top = { 0.0, 1.0, 0.0};
- static vector bottom = { 0.0, -1.0, 0.0};
- static vector right = { 1.0, 0.0, 0.0};
- static vector left = {-1.0, 0.0, 0.0};
- static vector center = { 0.0, 0.0, 0.0};
-
- /* array for cube vertices */
- static vector cube_point[8];
-
- /* has the cube been initialized */
- static Boolean cube_initialized = FALSE;
-
- void setcube(float x, float y, float z)
- {
- cube_point[1][0] = cube_point[2][0] =
- cube_point[5][0] = cube_point[6][0] = x/2.0;
-
- cube_point[0][0] = cube_point[3][0] =
- cube_point[4][0] = cube_point[7][0] = -x/2.0;
-
- cube_point[2][1] = cube_point[3][1] =
- cube_point[6][1] = cube_point[7][1] = y/2.0;
-
- cube_point[0][1] = cube_point[1][1] =
- cube_point[4][1] = cube_point[5][1] = -y/2.0;
-
- cube_point[0][2] = cube_point[1][2] =
- cube_point[2][2] = cube_point[3][2] = z/2.0;
-
- cube_point[4][2] = cube_point[5][2] =
- cube_point[6][2] = cube_point[7][2] = -z/2.0;
-
- cube_initialized = TRUE;
- }
-
- /* filled cube */
- void fcube(void)
- {
- if (! cube_initialized)
- setcube(CUBE_X, CUBE_Y, CUBE_Z);
-
- /* draw bottom facing polygon */
- bgnpolygon();
- n3f(bottom);
- v3f(cube_point[4]);
- v3f(cube_point[5]);
- v3f(cube_point[1]);
- v3f(cube_point[0]);
- endpolygon();
-
- /* draw left facing polygon */
- bgnpolygon();
- n3f(left);
- v3f(cube_point[3]);
- v3f(cube_point[7]);
- v3f(cube_point[4]);
- v3f(cube_point[0]);
- endpolygon();
-
- /* draw right facing polygon */
- bgnpolygon();
- n3f(right);
- v3f(cube_point[5]);
- v3f(cube_point[6]);
- v3f(cube_point[2]);
- v3f(cube_point[1]);
- endpolygon();
-
- /* draw top facing polygon */
- bgnpolygon();
- n3f(top);
- v3f(cube_point[6]);
- v3f(cube_point[7]);
- v3f(cube_point[3]);
- v3f(cube_point[2]);
- endpolygon();
-
- /* draw front facing polygon */
- bgnpolygon();
- n3f(front);
- v3f(cube_point[1]);
- v3f(cube_point[2]);
- v3f(cube_point[3]);
- v3f(cube_point[0]);
- endpolygon();
-
- /* draw back facing polygon */
- bgnpolygon();
- n3f(back);
- v3f(cube_point[6]);
- v3f(cube_point[5]);
- v3f(cube_point[4]);
- v3f(cube_point[7]);
- endpolygon();
- }
-
-
-
- /* number of polygons around the cross section of the cylinder */
- #define CYL_NUMC 20
-
- /* number of polygons down the length of the cylinder */
- #define CYL_NUML 10
-
- /* arrays for torus vertices and normals */
- static vector cyl_point[CYL_NUMC][CYL_NUML+1];
- static vector cyl_norm[CYL_NUMC][CYL_NUML+1];
-
- /* has the cylinder been initialized */
- static Boolean cylinder_initialized = FALSE;
-
-
- /* initialize a cylinder */
- static void initcylinder(
- vector point[CYL_NUMC][CYL_NUML+1], /* array of vertex data */
- vector norm[CYL_NUMC][CYL_NUML+1]) /* array of normal data */
- {
- int i,j;
- float theta,nx,ny;
- int numc = CYL_NUMC, numl = CYL_NUML;
-
- for (i = 0; i < numc; i++) {
- theta = 2.0*M_PI*(float)i/(float)numc;
-
- nx = fcos(theta);
- ny = fsin(theta);
-
- for (j = 0; j <= numl; j++) {
- point[i][j][0] = nx;
- point[i][j][1] = ny;
- point[i][j][2] =(float)j/(float)numl - .5;
-
- norm[i][j][0] = nx;
- norm[i][j][1] = ny;
- norm[i][j][2] = 0.0;
- }
- }
- }
-
-
- /* wireframe cylinder */
- void wcylinder(void)
- {
- int i,j;
- int numc = CYL_NUMC, numl = CYL_NUML;
-
- if (! cylinder_initialized) {
- initcylinder(cyl_point,cyl_norm);
- cylinder_initialized = TRUE;
- }
-
- for (i = 0; i < numl; i++)
- for (j = 0; j < numc; j++) {
- bgnclosedline();
- v3f(cyl_point[j][i]);
- v3f(cyl_point[(j+1)%numc][i]);
- v3f(cyl_point[j][i+1]);
- endclosedline();
-
- bgnclosedline();
- v3f(cyl_point[(j+1)%numc][i]);
- v3f(cyl_point[j][i+1]);
- v3f(cyl_point[(j+1)%numc][i+1]);
- endclosedline();
- }
- }
-
- /* filled cylinder */
- void fcylinder(void)
- {
- int i,j;
- int numc = CYL_NUMC, numl = CYL_NUML;
-
- if (! cylinder_initialized) {
- initcylinder(cyl_point,cyl_norm);
- cylinder_initialized = TRUE;
- }
-
- for (i = 0; i < numc; i++) {
- bgntmesh();
- n3f(cyl_norm[i][0]);
- v3f(cyl_point[i][0]);
- for (j = 0; j < numl; j++) {
- n3f(cyl_norm[(i+1)%numc][j]);
- v3f(cyl_point[(i+1)%numc][j]);
- n3f(cyl_norm[i][j+1]);
- v3f(cyl_point[i][j+1]);
- }
- n3f(cyl_norm[(i+1)%numc][numl]);
- v3f(cyl_point[(i+1)%numc][numl]);
- endtmesh();
- }
- }
-
- void
- main(void)
- {
- short attached;
- short value;
- int dev;
-
- attached = TRUE;
-
- if (getgdesc(GD_BITS_STENCIL) < 8)
- {
- fprintf(stderr, "This machine does not have enough stencil planes for this program.\n");
- exit(0);
- }
-
- initialize();
-
- while (TRUE)
- {
- while (qtest() || !attached)
- {
- dev = qread (&value);
- if ((dev == ESCKEY) && (value == 0))
- exit(0);
- else if (dev == REDRAW)
- {
- reshapeviewport();
- drawscene();
- }
- else if (dev == INPUTCHANGE)
- attached = value;
- } /* end while qtest or not attached */
- drawscene();
- } /* end while (TRUE) */
- } /* end main() */
-
- /* The initialize subroutine positions the window and specifies
- * its future constraints. The program is in double buffer
- * and RGB mode. The simplest lighting model is used.
- */
- void
- initialize(void)
- {
- long gid1;
- long xmax, ymax;
-
- xmax = getgdesc(GD_XPMAX);
- ymax = getgdesc(GD_YPMAX);
- prefposition( xmax/4, xmax*3/4, ymax/4, ymax*3/4 );
- gid1 = winopen ("stencil");
- minsize (xmax/10, ymax/10);
- keepaspect (xmax, ymax);
- winconstraints();
-
- doublebuffer();
- RGBmode();
- stensize ( 8 );
- gconfig();
- zbuffer(TRUE);
- subpixel(TRUE);
-
- qdevice (ESCKEY);
- qenter (REDRAW, gid1);
-
- mmode(MVIEWING);
- perspective( 450, (float)xmax/(float)ymax, 0.99, 10.0);
- lookat(0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0);
-
- def_simple_light_calc();
- use_simple_light_calc();
-
- }
-
- /*
- * The drawscene routine does the CSG. The basic algorithm is as
- * follows:
- * Turn off drawing.
- * Render the cube's z-values into the z-buffer planes.
- * Use the stencil and the z-buffer comparison hardware
- * to count how many times the cylinder is drawn in
- * front of the cube.
- * Wherever exactly one face of the cylinder is in front
- * of the cube (in other words, the cube is between
- * or inside the cylinder), force z-values to the
- * largest possible z, because these pixels are inside
- * the hole in the cube.
- * Render the cube's back faces into this hole as needed (to
- * clip the back of the cylinder).
- * Render the cylinder's z-values into this hole as needed.
- * Turn drawing on.
- * Render the cube and cylinder where their z-values equal
- * the values in the z-buffer planes.
- */
- void
- drawscene(void)
- {
- czclear(0x0, getgdesc(GD_ZMAX));
- sclear(0);
- pushmatrix();
- rot(15.0, 'y');
-
- /* turn color planes off until we're ready to draw */
- wmpack(0);
-
- /* render the cube into the z planes */
- frontface (FALSE);
- backface(TRUE);
- zfunction(ZF_LEQUAL);
- fcube();
-
- /* use the z-buffer comparison hardware to
- increment the stencil planes wherever either face of
- the cylinder is in front of the cube (the z-test
- passes), but don't update the z-buffer planes */
-
- stencil( TRUE, 0, SF_ALWAYS, 0xFF,
- ST_KEEP, ST_KEEP, ST_INCR );
- zwritemask(0);
- frontface (FALSE);
- backface(FALSE);
- pushmatrix();
- scale(0.2, 0.2, 12.0);
- fcylinder();
- popmatrix();
- zwritemask(0xFFFFFF);
-
- /* force z-values to infinity wherever the cube is inside the
- cylinder (wherever the stencil planes have a value of one */
- zfunction(ZF_ALWAYS);
- stencil( TRUE, 0x1, SF_EQUAL, 0xFF,
- ST_KEEP, ST_KEEP, ST_KEEP );
- scrrect();
-
- /* render back faces of cube into z planes where the hole
- is (the stencil test is still active). This will
- keep the cylinder from sticking out the back. */
- backface (FALSE);
- frontface (TRUE);
- zfunction(ZF_LEQUAL);
- fcube();
-
- /* render back faces of cylinder into z-buffer planes wherever
- stencil planes are 1 and z passes */
-
- stencil( TRUE, 0x1, SF_EQUAL, 0xFF,
- ST_KEEP, ST_KEEP, ST_KEEP );
- pushmatrix();
- scale(0.2, 0.2, 12.0);
- fcylinder();
- popmatrix();
-
- /* now draw - turn color planes on and set up z test to pass only
- if the incoming z equals the stored z. Turn off the
- stencil test. */
-
- stencil( FALSE, 0x0, SF_ALWAYS, 0xFF,
- ST_KEEP, ST_KEEP, ST_KEEP );
- zfunction (ZF_EQUAL);
- wmpack(0xFFFFFF);
- frontface (FALSE);
- backface (TRUE);
- lmbind(MATERIAL, 1);
- lmbind(BACKMATERIAL, 3);
- fcube();
-
- /* draw the BACK faces of the cylinder because we want
- to see the inside of it. */
- backface (FALSE);
- frontface (TRUE);
- pushmatrix();
- scale(0.2, 0.2, 12.0);
- lmbind(MATERIAL, 2);
- lmbind(BACKMATERIAL, 3);
- fcylinder();
- popmatrix();
-
- popmatrix();
- swapbuffers();
- }
-
- /*
- * scrrect()
- *
- * This routine forces the z-values of whatever it draws to
- * be getgdesc(GD_ZMAX). Then it draws a big polygon. Effectively,
- * this routine clears the z-values of every pixel it draws into to
- * the maximum z value. Since it does this by drawing a polygon
- * rather than calling zclear, it is affected by the current
- * stencil test. Thus in this program, it clears the cube's
- * z-values out of the z-buffer planes wherever the cube is
- * inside the cylinder (see the call to stencil which precedes
- * the call to scrrect in the drawscene routine).
- */
-
- static Matrix Identity = {
- {1.,0.,0.,0.},
- {0.,1.,0.,0.},
- {0.,0.,1.,0.},
- {0.,0.,0.,1.}};
-
- void
- scrrect(void)
- {
- static long verts[4][2] = {{-10,-10},{10,-10},{10,10},{-10,10}};
-
- pushmatrix();
- loadmatrix(Identity);
- translate(0., 0., -1.);
- lsetdepth(getgdesc(GD_ZMAX), getgdesc(GD_ZMAX));
- bgnpolygon();
- v2i (verts[0]);
- v2i (verts[1]);
- v2i (verts[2]);
- v2i (verts[3]);
- endpolygon();
-
- lsetdepth(getgdesc(GD_ZMIN), getgdesc(GD_ZMAX));
- popmatrix();
- }
-